// 从玲珑商店的API接口获取对应信息

// 关闭VSCode非必要报错
// ignore_for_file: non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_if_null_operators

import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:get/instance_manager.dart';
import 'package:linglong_store_flutter/utils/Global_Variables/global_application_state.dart';
import 'package:linglong_store_flutter/utils/Linyaps_App_Management_API/linyaps_app_manager.dart';
import 'package:linglong_store_flutter/utils/Linyaps_Store_API/linyaps_package_info_model/linyaps_package_info.dart';
import 'package:linglong_store_flutter/utils/Linyaps_Store_API/version_compare/version_compare.dart';

class LinyapsStoreApiService {

  // 初始化指定API总线链接地址
  static String serverHost_Store = "https://storeapi.linyaps.org.cn";
  static String serverHost_Repo = "https://mirror-repo-linglong.deepin.com";
  static String serverHost_RepoExtra = "https://cdn-linglong.odata.cc/icon/main";

  // 拿到GetX的全局应用信息
  static ApplicationState globalAppState = Get.find<ApplicationState>();

  // 进行系统架构更新
  static String os_arch = globalAppState.os_arch.value;
  static String repo_arch = globalAppState.repo_arch.value;
  
  // 获取首页连播图信息用函数
  static Future <List<LinyapsPackageInfo>> get_welcome_carousel_list () async {
    String serverUrl = "$serverHost_Store/visit/getWelcomeCarouselList";
    Dio dio = Dio();    // 新建Dio请求对象
    Map <String,dynamic> upload_data = {    // 准备请求数据
      "repo":"stable",
      "arch":repo_arch,
    };
    // 发送并获取请求
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data),
    );  
    dio.close();
    List <LinyapsPackageInfo> WelcomeCarouseApps = [];     // 新建具体化的欢迎应用列表
    int i=0;
    // 将API响应的信息经过精准切割,加入到欢迎应用列表中
    for (i=0;i<response.data['data'].length;i++) {
      WelcomeCarouseApps.add(
        LinyapsPackageInfo(
          id: response.data['data'][i]['appId'], 
          repoName: response.data['data'][i]['repoName'],
          name: response.data['data'][i]['zhName'], 
          categoryName: response.data['data'][i]['categoryName'], 
          version: response.data['data'][i]['version'], 
          Icon: response.data['data'][i]['icon'],
          description: response.data['data'][i]['description'], 
          arch: response.data['data'][i]['arch'], 
        ),
      );
    }
    return WelcomeCarouseApps;
  }

  // 获取首页最受欢迎的No.a到No.b的应用
  static Future <List<LinyapsPackageInfo>> get_welcome_app_list () async {
    String serverUrl = "$serverHost_Store/visit/getWelcomeAppList";
    Dio dio = Dio();    // 新建Dio请求对象
    Map <String,dynamic> upload_data = {    // 准备请求数据
      "repoName": "stable",
      "arch": "x86_64",
      "pageNo": 1,
      "pageSize": 10,
    };

    // 发送并获取请求
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data),
    );  
    dio.close();
    
    // 将API响应的信息经过精准切割,加入到应用列表中
    List<LinyapsPackageInfo> welcome_app_list = [];
    dynamic i;
    for (i in response.data['data']['records']) {
      welcome_app_list.add(
        LinyapsPackageInfo(
          id: i['appId'], 
          repoName: i['repoName'],
          name: i['zhName'], 
          version: i['version'], 
          Icon: i['icon'],
          description: i['description'], 
          arch: i['arch'], 
          categoryName: i['categoryName'], 
          module: i['module'],
          runtime: i['runtime'],
          createTime: i['createTime'],
        ),
      );
    }
    return welcome_app_list;    // 返回对应信息
  }

  // 获取排行榜里最新上架的前100个应用
  static Future <List<LinyapsPackageInfo>> get_newest_app_list () async {
    String serverUrl = "$serverHost_Store/visit/getNewAppList";
    Dio dio = Dio();    // 新建Dio请求对象
    Map <String,dynamic> upload_data = {    // 准备请求数据
      "repoName": "stable",
      "arch": repo_arch,
      "pageNo": 1,
      "pageSize": 100,
    };
    // 发送并获取请求
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data),
    );  
    dio.close();

    // 将API响应的信息经过精准切割,加入到应用列表中
    List <LinyapsPackageInfo> newest_app_list = [];
    int i=0;
    for (i=0;i<response.data['data']['records'].length;i++) {
      newest_app_list.add(
        LinyapsPackageInfo(
          id: response.data['data']['records'][i]['appId'], 
          repoName: response.data['data']['records'][i]['repoName'],
          name: response.data['data']['records'][i]['zhName'], 
          version: response.data['data']['records'][i]['version'], 
          Icon: response.data['data']['records'][i]['icon'],
          description: response.data['data']['records'][i]['description'], 
          arch: response.data['data']['records'][i]['arch'], 
          categoryName: response.data['data']['records'][i]['categoryName'], 
          module: response.data['data']['records'][i]['module'],
          runtime: response.data['data']['records'][i]['runtime'],
          createTime: response.data['data']['records'][i]['createTime'],
        ),
      );
    }
    return newest_app_list;
  }

  // 获取排行榜里下载量最高的前100个应用
  static Future <List<LinyapsPackageInfo>> get_most_downloaded_app_list () async {
    String serverUrl = "$serverHost_Store/visit/getInstallAppList";
    Dio dio = Dio();    // 新建Dio请求对象
    Map <String,dynamic> upload_data = {    // 准备请求数据
      "repoName": "stable",
      "arch": repo_arch,
      "pageNo": 1,
      "pageSize": 100,
    };
    // 发送并获取请求
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data),
    );  
    dio.close();

    // 将API响应的信息经过精准切割,加入到应用列表中
    List <LinyapsPackageInfo> most_downloaded_app_list = [];
    dynamic i;
    for (i in response.data['data']['records']) {
      most_downloaded_app_list.add(
        LinyapsPackageInfo(
          id: i['appId'], 
          repoName: i['repoName'],
          name: i['zhName'], 
          version: i['version'], 
          Icon: i['icon'],
          description: i['description'], 
          arch: i['arch'], 
          categoryName: i['categoryName'], 
          module: i['module'],
          runtime: i['runtime'],
          createTime: i['createTime'],
          installCount: i['installCount'],
        ),
      );
    }
    return most_downloaded_app_list;
  }

  // 用于获取所有应用的方法
  ///
   // 获取从startPage页开始,一页数量为pageSize里的应用信息,之所以要加入app_list是因为每次获取到的应用信息都是叠加的
   // 举个例子,startPage = 2,pageSize = 100就是说明显示从第101个到第200个应用
   ///
  static Future <List <LinyapsPackageInfo>> get_app_list (int startPage,int pageSize) async {
    String serverUrl = "$serverHost_Store/visit/getSearchAppList";
    Dio dio = Dio();    // 新建Dio请求对象
    Map <String,dynamic> upload_data = {    // 准备请求数据
      "repoName": "stable",
      "arch": repo_arch,
      "pageNo": startPage,
      "pageSize": pageSize,
    };

    // 发送并获取请求
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data),
    );  
    dio.close();

    // 初始化获取到的所有应用信息列表
    List <LinyapsPackageInfo> app_list = [];

    // 将API响应的信息经过精准切割,加入到应用列表中
    dynamic i;
    for (i in response.data['data']['records']) {
      app_list.add(
        LinyapsPackageInfo(
          id: i['appId'], 
          repoName: i['repoName'],
          name: i['zhName'], 
          version: i['version'], 
          Icon: i['icon'],
          description: i['description'], 
          arch: i['arch'], 
          categoryName: i['categoryName'], 
          channel: i['channel'],
          module: i['module'],
          runtime: i['runtime'],
        ),
      );
    }
    return app_list;
  }

  // 获取用户搜索结果的后端对接方法
  static Future <List<LinyapsPackageInfo>> get_search_results (String searchId) async {
    String serverUrl = '$serverHost_Store/visit/getSearchAppList';
    Dio dio = Dio ();    // 创建Dio请求对象
    Map <String,dynamic> upload_data = {    // 准备请求数据
      "repoName": "stable",
      "name": searchId,
      "arch": repo_arch,
      "pageNo": 1,
      "pageSize": 100,
    };
    // 发送并获取返回结果
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data),
    );  
    dio.close();

    List <dynamic> search_info_get = response.data['data']['records'];

    // 循环加入最终结果对象中
    List <LinyapsPackageInfo> returnItems = [];
    dynamic i;
    for (i in search_info_get) {
      returnItems.add(
        LinyapsPackageInfo(
          id: i['id']==null?i['appId']:i['id'], 
          name: i['name'], 
          version: i['version'], 
          description: i['description'], 
          arch: i['arch'],
          Icon: i['icon'],
          channel: i['channel'],
          module: i['module'],
          categoryName: i['categoryName'],
          installCount: i['installCount'],
        ),
      );
    }
    // 直接以玲珑包类返回结果
    return returnItems;
  }

  // 获取具体应用的详细信息的方法2: 此方法是仅返回应用的最新版本信息
  // 当能获取到应用信息时返回对应类, 否则返回null
  static Future <LinyapsPackageInfo?> get_app_detail_latest (String appId) async {  
    // 指定具体响应API地址
    String serverUrl = '$serverHost_Store/app/getAppDetail';
    // 创建Dio请求对象
    Dio dio = Dio ();    
    // 准备请求数据
    Map <String,dynamic> upload_data = {   
      "appId": appId,
      "arch": repo_arch
    };
    List <Map<String, dynamic>> upload_data_list = [];
    upload_data_list.add(upload_data);
    // 发送并获取返回信息
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data_list),
    );  
    dio.close();

    // 在这里提前读获取的应用信息,若为Null直接返回
    if (response.data['data'][appId] == null) return null;
    Map <dynamic,dynamic> app_info_get = response.data['data'][appId][0];
    
    // 进行解析并返回应用详情
    return LinyapsPackageInfo(
      id: app_info_get['appId'], 
      name: app_info_get['name'], 
      arch: repo_arch,
      version: app_info_get['version'], 
      description: app_info_get['description'], 
      createTime: app_info_get['createTime'], 
      Icon: app_info_get['icon'],
    );
  }

  // 单开获取本地应用图标的函数, 同步进行减少应用加载时间
  static Future <List<LinyapsPackageInfo>> updateAppIcon (List<LinyapsPackageInfo> installed_apps) async {
    // 指定具体响应API地址
    String serverUrl = '$serverHost_Store/app/getAppDetail';
    
    // 初始化待提交应用
    List <Map<String, String>> upload_installed_apps = [];
    for (dynamic i in installed_apps) {
      upload_installed_apps.add({
        'appId': i.id,
        'arch': repo_arch
      });
    }
    // 创建Dio请求对象
    Dio dio = Dio ();    
    // 发送并获取返回信息
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_installed_apps),
    );  
    dio.close();

    Map <String, dynamic> app_info_get = response.data['data'];
    // 拿到请求后准备逐个返回
    List <LinyapsPackageInfo> returnItems = [];
    int i=0;
    for (LinyapsPackageInfo cur_app_info in installed_apps) {
      // 不管其他,先加入元素
      returnItems.add(cur_app_info);
      String? IconUrl;
      if (app_info_get.containsKey(returnItems[i].id)) {
        IconUrl = app_info_get[returnItems[i].id][0]['icon'];
        returnItems[i].Icon = IconUrl;
      }
      i++;
    }

    return returnItems;
  }

  // 返回应用可更新列表
  static Future <List<LinyapsPackageInfo>> get_upgradable_apps () async {
    // 指定具体响应API地址
    String serverUrl = '$serverHost_Store/app/getAppDetail';

    List <LinyapsPackageInfo> installed_apps = await LinyapsAppManagerApi.get_installed_apps([]);
    // 初始化待提交应用
    List <Map<String, String>> upload_installed_apps = [];
    for (dynamic i in installed_apps) {
      upload_installed_apps.add({
        'appId': i.id,
        'arch': repo_arch
      });
    }
    // 创建Dio请求对象
    Dio dio = Dio ();    
    // 发送并获取返回信息
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_installed_apps),
    );  
    Map <String, dynamic> app_info_get = response.data['data'];

    // 初始化待返回应用抽象类列表
    List <LinyapsPackageInfo> upgradable_apps = [];

    // 遍历已安装的应用
    LinyapsPackageInfo i;   // 先初始化遍历用迭代器
    for (i in installed_apps) {
      // 先尝试从商店获取当前应用信息,若没有则直接返回空对象
      LinyapsPackageInfo app_info_from_store = app_info_get.containsKey(i.id)
        ? LinyapsPackageInfo(
          id: app_info_get[i.id][0]['appId'], 
          name: app_info_get[i.id][0]['name'], 
          version: app_info_get[i.id][0]['version'], 
          description: app_info_get[i.id][0]['description'], 
          Icon: app_info_get[i.id][0]['icon'],
          arch: repo_arch,
        )
        : LinyapsPackageInfo(
          id: '', 
          name: '', 
          version: '', 
          description: '', 
          arch: ''
        );
      // 如果找不到对应应用,或者发现是base则直接跳过
      if (
        app_info_from_store.id == '' || 
        app_info_from_store.id == 'org.deepin.base' || 
        app_info_from_store.id == 'org.deepin.foundation' ||
        app_info_from_store.id == 'org.deepin.Runtime' ||
        app_info_from_store.id == 'org.deepin.runtime.dtk' || 
        app_info_from_store.id == 'org.deepin.runtime.gtk4' ||
        app_info_from_store.id == 'org.deepin.base.flatpak.freedesktop' ||
        app_info_from_store.id == 'org.deepin.base.flatpak.kde' ||
        app_info_from_store.id == 'org.deepin.base.flatpak.gnome' ||
        app_info_from_store.id == 'org.deepin.base.wine' ||
        app_info_from_store.id == 'org.deepin.runtime.wine' ||
        app_info_from_store.id == 'org.deepin.runtime.qt5' ||
        app_info_from_store.id == 'org.deepin.runtime.webengine'
      ) continue;
      // 如果发现有更高版本
      if (
        VersionCompare.isFirstGreaterThanSec(
          app_info_from_store.version,
          i.version
        )
      ) {
        // 存储最新版本应用的信息
        upgradable_apps.add(
          LinyapsPackageInfo(
            id: i.id, 
            name: i.name, 
            version: app_info_from_store.version, 
            current_old_version: i.version,
            description: i.description, 
            arch: i.arch,
            Icon: app_info_from_store.Icon,
          ),
        );
      }
    }
    return upgradable_apps;
  }

  // 获取具体应用的详细信息的方法2: 此方法是返回一个应用的每个版本的列表信息
  static Future <List<LinyapsPackageInfo>> get_app_details_list (String appId) async {
    // 指定具体响应API地址
    String serverUrl = '$serverHost_Store/app/getAppDetail';
    Dio dio = Dio ();    // 创建Dio请求对象
    // 由于该API强制要求列表形式添加故在这里也使用列表形式
    List<Map<String,dynamic>> upload_data = [];
    upload_data.add({
      "appId": appId,
      "arch": repo_arch,
    });

    // 发送并获取返回信息
    Response response = await dio.post(
      serverUrl,
      data: jsonEncode(upload_data),
    );  
    dio.close();

    // 如果发现返回的应用信息为null则直接返回空列表
    if (response.data['data'] == null) return [];

    // 如果获取信息不为空则拿到信息
    List <dynamic> app_info_get = response.data['data'][appId];

    // 将返回的信息变成玲珑应用类的列表
    List <LinyapsPackageInfo> cur_app_info = [];

    // 提前初始化i变量
    for (dynamic i in app_info_get) {
      cur_app_info.add(
        LinyapsPackageInfo(
          id: i['appId'] ?? '', 
          devName: i['devName'],
          name: i['name'], 
          zhName: i['zhName'],
          base: i['base'] ?? '', 
          installCount: i['installCount'],
          runtime: i['runtime'],
          repoName: i['repoName'],
          channel: i['channel'],
          module: i['module'],
          version: i['version'], 
          description: i['description'], 
          arch: i['arch'],
          Icon: i['icon'],  
        ),
      );
    }
    // 最终从服务器返回必需的信息
    return cur_app_info;
  }
}

/**
// 备份用的二分查找算法
if (app_info_get.isNotEmpty) {
  for (i=0;i<app_info_get.length;i++) {
    LinyapsPackageInfo wait_add_info = LinyapsPackageInfo(
      id: app_info_get[i]['id']==null?app_info_get[i]['appId']:app_info_get[i]['id'], 
      devName: app_info_get[i]['devName'],
      name: app_info_get[i]['name'], 
      base: app_info_get[i]['base'], 
      installCount: app_info_get[i]['installCount'],
      runtime: app_info_get[i]['runtime'],
      repoName: app_info_get[i]['repoName'],
      channel: app_info_get[i]['channel'],
      module: app_info_get[i]['module'],
      version: app_info_get[i]['version'], 
      description: app_info_get[i]['description'], 
      arch: app_info_get[i]['arch'],
      Icon: app_info_get[i]['icon'],  
    );
    
    // 使用二分查找找到合适的插入位置
    if (cur_app_info.isEmpty) cur_app_info.add(wait_add_info);
    else {
      // 使用二分法寻找待插入节点
      int left = 0;
      int right = cur_app_info.length - 1;
      while (left<=right)
        {
          // 存储中间节点
          int m =(left + right) ~/ 2;
          // 如果中间节点大于待插入节点
          if (
            VersionCompare(
              ver1: cur_app_info[m].version, 
              ver2: wait_add_info.version,
            ).isFirstGreaterThanSec()
          ) {
            right=m-1;
          }
          else left=m+1;
        }
      // 最后插入待插入节点
      // 特殊处理最后一个让用专用的插入函数,因为insert不支持在末尾追加,这样会导致原先的最后一个元素被往后挤
      if (left<cur_app_info.length) cur_app_info.insert(left,wait_add_info);
      else cur_app_info.add(wait_add_info);
    }    
  }
  // 返回对应信息
  return cur_app_info;
} 
else return [];
*/
